home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*_________________________________________________________________________
- |
- | maze.c - maze creation and drawing routines
- |
- |
- | init_maze() used to read the maze data from the file maze.dat
- | build_maze() builds the objects from the data
- | draw_maze() draws the maze for you by calling all its objects
- | free_arcs() deletes the generated objects for the active level
- |
- | the maze itself is a nested structure of type maze_t defined in maze.h
- |
- | (c) 1994 Frans van Hoesel, Xtreme graphics software
- |
- */
-
-
-
- #include <alloca.h>
- #include <gl/gl.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <math.h>
- #include <fcntl.h>
- #include <string.h>
- #include <bstring.h>
- #include <ctype.h>
- #include <stdarg.h>
- #include "config.h"
- #include "io.h"
- #include "blixvect.h"
- #include "lod.h"
- #include "maze.h"
- #include "mymath.h"
- #include "rand.h"
- #include "blixsound.h"
-
- /*_________________________________________________________________________
- |
- | static variables and constants used while reading the maze.dat data file
- |
- */
-
- #define MAXLEVEL 5
- #define MAXCENTER 20
- #define MAXCIRCLE 10
- #define MAXNODES 1600
- #define MAXARC 20
-
- /* local typedefs and declarations */
-
- static int read_maze(maze_t *maze);
- static int read_level(level_t *level);
- static int read_center(center_t *center);
- static int read_circle(circle_t *circle);
- static void read_nodes(node_t *nodes);
- static int read_node(node_t *node);
- static void free_maze(maze_t *maze);
- static void connect_nodes(const int n1, const int n2);
-
- #ifdef BUILDNODES
- static void build_nodes(node_t *nodes);
- static int add_node(const float *p, const int num);
- static int check_node(float p[3], Matrix *m, int cent);
- #endif
-
- /* static variables */
- static Object lastobject = 0;
-
- extern int can_do_textures;
- extern int Lod;
- maze_t the_maze;
- level_t the_level;
- node_t *the_nodes;
- int the_nnodes;
- /*________________________________________________________________________
- |
- | init_maze - public functiona that reads maze data from file
- |
- | call this before you try to do anything else with the maze
- */
-
- void init_maze(void) {
- read_maze(& the_maze);
- }
-
- /*________________________________________________________________________
- |
- | read_maze - read maze data from file
- |
- | it opens the file "maze.dat" then repeatedly calls read_level,
- | until that function returns
- | EOF
- */
-
-
- static int read_maze(maze_t *maze) {
-
- level_t this_level;
- level_t *level_ptr;
- int cnt = 0;
- center_t these_centers[MAXCENTER];
- node_t these_nodes[MAXNODES];
- static int read_before = FALSE;
-
-
- if (read_before == TRUE) {
- /* free allocated memory and delete related GL-objects */
- free_maze(maze);
- }
- the_nnodes = 0;
-
- read_before = TRUE;
- this_level.ncenters = 0;
- this_level.centers = these_centers;
- this_level.nodes = these_nodes;
-
- open_file("maze.dat");
- read_before = TRUE;
- maze->levels = (level_t *)malloc(MAXLEVEL * sizeof(level_t));
- skipblanks();
- level_ptr = maze->levels;
- maze->nlevels = 0;
- while (cnt++ < MAXLEVEL && read_level(&this_level) != EOF) {
- /* check that levels are specified in order */
- if (this_level.leveln != cnt)
- errormsg("levels must be specifies in order");
- maze->nlevels += 1;
-
- /* copy level, but don't allocate more then really needed */
- *level_ptr = this_level;
- level_ptr->centers = (center_t *)malloc(this_level.ncenters *
- sizeof(center_t));
- bcopy(this_level.centers, level_ptr->centers,
- this_level.ncenters * sizeof(center_t));
- level_ptr->nodes = (node_t *)malloc(this_level.nnodes *
- sizeof(node_t));
- bcopy(this_level.nodes, level_ptr->nodes, this_level.nnodes *
- sizeof(node_t));
- the_nodes = level_ptr->nodes;
- level_ptr++;
- }
- close_file();
-
- return 0;
- }
-
- /*________________________________________________________________________
- |
- | read_level - read a level from file
- |
- | Reads a level by reading one center in a local declared center
- | (this_center) and then malloc the space needed to add it to the level
- | structure. Repead that until the read_center function fails.
- */
-
- static int read_level (level_t *level) {
-
- center_t this_center;
- center_t *center_ptr;
- int cnt = 0;
- circle_t these_circles[MAXCIRCLE];
-
- this_center.ncircles = 0;
- this_center.circles = these_circles;
- if (read_str("level"))
- return EOF;
- expect_ch('(');
- if (test_ch(')')==0) {
- /* accept the integer indicating the level, but ignore it
- * Levels must be specified in order.
- */
- level->leveln = accept_int();
- }
- expect_ch(')');
- expect_ch(';');
- center_ptr = level->centers;
- level->ncenters = 0;
- while (cnt++ < MAXCENTER && read_center(&this_center) != EOF) {
- level->ncenters += 1;
-
- /* copy center, but don't allocate more then really needed */
- *center_ptr = this_center;
- center_ptr->circles = (circle_t *)malloc(this_center.ncircles *
- sizeof(circle_t));
- bcopy(this_center.circles, center_ptr->circles,
- this_center.ncircles * sizeof(circle_t));
- center_ptr->radius =
- this_center.circles[this_center.ncircles-1].cradius;
- center_ptr++;
- }
- the_nnodes = 0;
- the_nodes = level->nodes;
- the_level = *level;
- read_nodes(the_nodes);
- /*
- # ifdef BUILDNODES
- the_nnodes = 0;
- build_nodes(the_nodes);
- # endif
- */
- level->nnodes = the_nnodes;
- return 0;
- }
-
- static void read_nodes(node_t *nodes) {
- the_nnodes = 0;
- while (the_nnodes < MAXNODES && read_node(nodes) != EOF) {
- nodes++;
- the_nnodes++;
- }
- }
-
- static int read_node(node_t *node) {
- int i;
- int nodenum, connect;
- skipblanks();
-
- if (read_str("node")) {
- return EOF;
- }
- expect_ch('(');
- nodenum = accept_int();
- expect_ch(',');
- i = accept_int();
- node->special.all = 0;
- if (i & 0x10 ) {
- node->special.b.ndir = 1;
- node->special.b.ptype = i & 0x0f;
- } else {
- node->special.b.ptype = i & 0x0f;
- }
- node->special.b.magic = (i & 0xfffff00) >> 8;
- expect_ch(',');
- node->pos[0] = accept_float();
- expect_ch(',');
- node->pos[1] = accept_float();
- expect_ch(',');
- node->pos[2] = accept_float();
- vnormal(node->pos);
- i = 0;
- skipblanks();
- while (test_ch(')')==0 && i < 4) {
- expect_ch(',');
- connect = accept_int();
- (node->c)[i] = connect;
- if (connect < nodenum)
- connect_nodes(connect, nodenum);
- i++;
- }
- node->cnt = i;
- while (i < 4) {
- (node->c)[i] = -1;
- i++;
- }
- expect_ch(')');
- expect_ch(';');
- return 0;
- }
-
-
- static int read_center (center_t *center) {
-
- circle_t this_circle;
- circle_t *circle_ptr;
- int cnt = 0;
- float rotation;
- arc_t these_arcs[MAXARC];
- float these_walls[MAXARC];
- float these_gaps[MAXARC];
- int these_cappings[MAXARC];
-
- this_circle.narcs = 0;
- this_circle.arcs = these_arcs;
- this_circle.walls = these_walls;
- this_circle.gaps = these_gaps;
- this_circle.cappings = these_cappings;
-
- skipblanks();
- if (read_str("center"))
- return EOF;
- expect_ch('(');
- center->center_v[0] = accept_float();
- expect_ch(',');
- center->center_v[1] = accept_float();
- expect_ch(',');
- center->center_v[2] = accept_float();
- expect_ch(',');
- center->axis_v[0] = accept_float();
- expect_ch(',');
- center->axis_v[1] = accept_float();
- expect_ch(',');
- center->axis_v[2] = accept_float();
- expect_ch(')');
- expect_ch(';');
- circle_ptr = center->circles;
- center->ncircles = 0;
- while (cnt++ < MAXCENTER && read_circle(&this_circle) != EOF) {
- center->ncircles += 1;
- /* copy circle, but don't allocate more then really needed */
- *circle_ptr = this_circle;
- circle_ptr->arcs = (arc_t *)malloc(this_circle.narcs * sizeof(arc_t));
- circle_ptr->walls = (float *)malloc(this_circle.narcs * sizeof(float));
- circle_ptr->gaps = (float *)malloc(this_circle.narcs * sizeof(float));
- circle_ptr->cappings = (int *)malloc(this_circle.narcs * sizeof(int));
- bcopy(this_circle.arcs, circle_ptr->arcs,
- this_circle.narcs * sizeof(arc_t));
- bcopy(this_circle.walls, circle_ptr->walls,
- this_circle.narcs * sizeof(float));
- bcopy(this_circle.gaps, circle_ptr->gaps,
- this_circle.narcs * sizeof(float));
- bcopy(this_circle.cappings, circle_ptr->cappings,
- this_circle.narcs * sizeof(int));
- /* find its cartesian radius */
- rotation = this_circle.start[0];
- vrot_axis(center->center_v, center->axis_v,
- (center->ncircles-1+0.4508) * PI_DEPTH, circle_ptr->start);
- vrot_axis(circle_ptr->start, center->center_v,
- rotation , circle_ptr->start);
-
- circle_ptr->cradius = vdistance(circle_ptr->start, center->center_v);
-
- circle_ptr++;
- }
- return 0;
- }
-
-
- static int read_circle (circle_t *circle) {
-
- float *wall_ptr;
- float *gap_ptr;
- int *capping_ptr;
-
- int cnt = 0;
-
- float total_angle = 0;
-
- skipblanks();
- if (read_str("circle"))
- return EOF;
- expect_ch('(');
- /* store the overall rotation temporarely in start[0]; the actual
- * starting point wich results from this is calculated in the calling
- * function read_center()
- */
- circle->start[0] = accept_float();
- wall_ptr = circle->walls;
- gap_ptr = circle->gaps;
- capping_ptr = circle->cappings;
- circle->narcs = 0;
- do {
- skipblanks();
- if (read_ch('|') == 0) {
- *capping_ptr = 1;
- } else if (read_ch(',') == 0) {
- *capping_ptr = 0;
- } else
- errormsg("comma or '|' expected");
- *wall_ptr = accept_float();
- skipblanks();
- if (read_ch('|') == 0) {
- *capping_ptr |= 2;
- } else if (read_ch(',') == 0) {
- ;
- } else
- errormsg("comma or '|' expected");
- *gap_ptr = accept_float();
- circle->narcs += 1;
- total_angle += *wall_ptr + *gap_ptr;
- wall_ptr++;
- gap_ptr++;
- capping_ptr++;
- skipblanks();
- } while (++cnt < MAXARC && read_ch(')'));
- if (fabs (PI2 -total_angle) > 0.1) {
- warningmsg(" angles don't add up "
- "to 2 * pi (%f).\n", total_angle);
- }
- *(circle->walls) = PI2 - total_angle + *(circle->walls);
- expect_ch(';');
- return 0;
- }
-
-
- /*____________________________________________________________________________
- |
- | build_arc - create a gl object for the walls
- |
- | if you want different walls, change that here.
- |
- */
-
- static void build_arc(const float center[3], const float start[3],
- float stepangle, const float angle, int cap, int lod, arc_t *w,
- float end[3]) {
-
- #define MAXSEG 85
-
- segment_t *s, *sprev;
- segment_t seg[MAXSEG];
-
- float t1[3], t2[3], wd[3];
- float st[2];
- Matrix m;
- int nstep, i, j;
-
- nstep = (int) (angle / stepangle );
- if (nstep == 0)
- nstep = 1;
- if (nstep >= MAXSEG -1) {
- printf("too many segments\n");
- exit(1);
- }
- s = seg;
-
- mmake_rot_axis(center, -angle/ nstep, m);
- vcopy(start, end);
- vcross(start, center, t1);
- vcross(start, t1, t2);
- vnormal(t2);
- vcopy(t2, wd);
- vcopy(wd, s->n0);
- vcopy(wd, s->n2);
- vscalar(s->n2, -1.0);
- vscalar(wd, WIDTH / 2.0);
- if (lod >= WALLS_UP) {
- vcopy(start, t1);
- vscalar(t1, 0.989);
- vadd(t1, wd, s->w0);
- vsub(t1, wd, s->w1);
- } else {
- vadd(start, wd, s->w0);
- vsub(start, wd, s->w1);
- }
- vcopy(start, s->n1);
- vcopy(start, t1);
- vscalar(t1, 1.0 + MAXHEIGHT);
- vadd(t1, wd, s->w2);
- vsub(t1, wd, s->w3);
-
- /* tilt the normal a bit so we get some more light in the scene */
- vcopy(s->n1, t1);
- vscalar(t1, 0.1);
- vadd(s->n0, t1, s->n0);
- vnormal(s->n0);
- vadd(s->n2, t1, s->n2);
- vnormal(s->n2);
-
-
- sprev = s;
- s++;
- for (i=1; i <= nstep; i++) {
- vtransform(end, m, end);
- vtransform(sprev->w0, m, s->w0);
- vtransform(sprev->w1, m, s->w1);
- vtransform(sprev->n1, m, s->n1);
- if (lod >= WALLS_UP) {
- vtransform(sprev->w2, m, s->w2);
- vtransform(sprev->w3, m, s->w3);
- vtransform(sprev->n0, m, s->n0);
- vtransform(sprev->n2, m, s->n2);
- }
- sprev = s;
- s++;
- }
- s = seg;
- if (lod >= WALLS_UP) {
- lastobject++;
- w->wall_obj = lastobject;
- makeobj(w->wall_obj);
- /*cpack(0x00012488);*/
- bgnqstrip();
- /* inside wall */
- for (j =0; j<= nstep; j++) {
- n3f(s->n0);
- if (lod >= TEXTURE_MAPS && can_do_textures) {
- if (lod >= EXTRA_FINE) {
- st[0] = j * 0.4;
- } else {
- st[0] = j * 1.2;
- }
- st[1] = 0;
- t2f(st);
- v3f(s->w2);
- st[1] = 1;
- t2f(st);
- } else {
- v3f(s->w2);
- }
- v3f(s->w0);
- s++;
- }
- endqstrip();
-
- s = seg;
- /* starting cap */
- if (cap & 1) {
- /* put cap on starting segment of wall */
- vsub(s->w0, (s+1)->w0, t1);
- vnormal(t1); /* this is the approximate normal */
- bgnqstrip();
- n3f(t1);
- v3f(s->w2);
- v3f(s->w3);
- v3f(s->w0);
- v3f(s->w1);
- endqstrip();
- }
-
- /* outside wall */
- bgnqstrip();
- for (j =0; j<= nstep; j++) {
- n3f(s->n2);
- if (lod >= TEXTURE_MAPS && can_do_textures) {
- if (lod >= EXTRA_FINE) {
- st[0] = j * 0.4;
- } else {
- st[0] = j * 1.2;
- }
- st[1] = 0;
- t2f(st);
- v3f(s->w1);
- st[1] = 1;
- t2f(st);
- } else {
- v3f(s->w1);
- }
- v3f(s->w3);
- s++;
- }
- endqstrip();
-
- /* end cap */
- s--;
- if (cap & 2) {
- /* put cap on last segment of wall */
- vsub(s->w0, (s-1)->w0, t1);
- vnormal(t1); /* this is the approximate normal */
- bgnqstrip();
- n3f(t1);
- v3f(s->w0);
- v3f(s->w1);
- v3f(s->w2);
- v3f(s->w3);
- endqstrip();
- }
- closeobj();
- lastobject++;
- w->top_obj = lastobject;
- makeobj(w->top_obj);
- /* top wall */
- s = seg;
- /*cpack(0x004f1024);*/
- bgnqstrip();
- for (j =0; j<= nstep; j++) {
- n3f(s->n1);
- v3f(s->w3);
- v3f(s->w2);
- s++;
- }
- endqstrip();
- } else {
- /* very low level of detail, create only a flat maze */
- s = seg;
- lastobject++;
- w->top_obj = lastobject;
- w->wall_obj = 0;
- makeobj(w->top_obj);
- /*cpack(0x004f1024);*/
- bgnqstrip();
- for (j =0; j<= nstep; j++) {
- n3f(s->n1);
- v3f(s->w1);
- v3f(s->w0);
- s++;
- }
- endqstrip();
- }
- closeobj();
- }
-
- /*________________________________________________________________________
- |
- | build_maze - traverses the maze structure, and creates gl-objects
- |
- | the gl-objects created are already spherical, no additional rotation,
- | except the overall rotation of the sphere is needed.
- | the Level of the maze is specified in the first parameter; the
- | amount of detail present is varied with the 'Level-Of-Detail
- | parameter.
- */
-
- void build_maze(int level, int lod) {
-
- int i, j, k;
- float start[3];
-
- level_t *levl_ptr;
- center_t *cent_ptr;
- circle_t *circ_ptr;
- arc_t *arc_ptr;
- float *wall_ptr;
- float *gap_ptr;
- int *capping_ptr;
- int ncirc, narc;
- float st_angle;
- static int prevlevel = -1;
- static float stepangle[MAXCIRCLE] = {
- 0.314, 0.235, 0.196, 0.157079, 0.157079,
- 0.157079, 0.157079, 0.157079, 0.157079, 0.157079 };
-
-
- levl_ptr = the_maze.levels+level;
- the_level = *levl_ptr;
- the_nodes = levl_ptr->nodes;
- the_nnodes = levl_ptr->nnodes;
- if (the_level.leveln != prevlevel) {
- prevlevel = the_level.leveln;
- }
- cent_ptr = levl_ptr->centers;
-
- lastobject = 0;
-
- for (i = 0; i< levl_ptr->ncenters; i++) {
- circ_ptr = cent_ptr->circles;
- ncirc = cent_ptr->ncircles;
- for (j=0; j< ncirc; j++) {
- arc_ptr = circ_ptr->arcs;
- narc = circ_ptr->narcs;
- wall_ptr = circ_ptr->walls;
- gap_ptr = circ_ptr->gaps;
- capping_ptr = circ_ptr->cappings;
- st_angle = stepangle[j];
- if (lod >= EXTRA_FINE) st_angle /= 3;
- if (lod <= EXTRA_COARSE && lod >= WALLS_UP) st_angle *= 2;
- vcopy(circ_ptr->start, start);
- for (k = 0 ; k< narc; k++) {
- build_arc(cent_ptr->center_v, start, st_angle,
- *wall_ptr++, *capping_ptr++, lod, arc_ptr, start);
- arc_ptr++;
- vrot_axis(start, cent_ptr->center_v, *gap_ptr++ , start);
- }
- circ_ptr++;
- }
- cent_ptr++;
- }
- }
-
- #ifdef BUILDNODES
- static int add_node(const float *p, const int centnum) {
-
- int i;
- for (i=0; i< the_nnodes; i++) {
- if (the_nodes[i].cnt == -1) {
- /* found an unused node, so use it */
- vcopy(p, the_nodes[i].pos);
- the_nodes[i].c[0] = -1;
- the_nodes[i].c[1] = -1;
- the_nodes[i].c[2] = -1;
- the_nodes[i].c[3] = -1;
- the_nodes[i].special.all = 0;
- the_nodes[i].player = NULL;
- the_nodes[i].cnt = 0;
- return i;
- }
- }
- vcopy(p, the_nodes[the_nnodes].pos);
- the_nodes[the_nnodes].c[0] = -1;
- the_nodes[the_nnodes].c[1] = -1;
- the_nodes[the_nnodes].c[2] = -1;
- the_nodes[the_nnodes].c[3] = -1;
- the_nodes[the_nnodes].special.all = 0;
- the_nodes[i].player = NULL;
- the_nodes[the_nnodes].cnt = 0;
- the_nnodes++;
- return (the_nnodes-1);
- }
- #endif
-
-
- static void connect_nodes(const int n1, const int n2) {
- int i, j;
-
- i=0;
- if (n1 == n2) {
- fprintf(stderr, "trying to connect node %d to itself\n", n1);
- return;
- }
- while (i<4 && the_nodes[n1].c[i] >= 0) {
- if ( the_nodes[n1].c[i] == n2) /* check if already connected */
- return;
- i++;
- }
- if (i == 4) {
- fprintf(stderr,
- "cannot make more connections to node %d (from %d)\n", n1, n2);
- return;
- }
- j=0;
- while (j<4 && the_nodes[n2].c[j] >= 0) {
- if ( the_nodes[n2].c[j] == n1) /* check if already connected */
- return;
- j++;
- }
- if (j == 4) {
- fprintf(stderr,
- "cannot make more connections to node %d (from %d)\n", n2, n1);
- return;
- }
- the_nodes[n1].c[i] = n2;
- the_nodes[n2].c[j] = n1;
- the_nodes[n1].cnt++;
- the_nodes[n2].cnt++;
- }
-
-
- #ifdef BUILDNODES
- static void disconnect_nodes(const int n1, const int n2) {
- int i, j;
-
- i=0;
- while (i<4 && the_nodes[n1].c[i] != n2)
- i++;
- if (i==4) {
- fprintf(stderr,
- "trying to disconnect unconnected nodes %d, %d\n", n1, n2);
- return;
- }
- while (i<3) {
- the_nodes[n1].c[i] = the_nodes[n1].c[i+1];
- i++;
- }
- the_nodes[n1].c[3] = -1;
- the_nodes[n1].cnt --;
- if (the_nodes[n1].cnt == 0)
- the_nodes[n1].cnt = -1;
- j = 0;
- while (j<4 && the_nodes[n2].c[j] != n1)
- j++;
- if (j==4) {
- fprintf(stderr,
- "trying to disconnect unconnected nodes %d, %d\n", n1, n2);
- return;
- }
- while (j<3) {
- the_nodes[n2].c[j] = the_nodes[n2].c[j+1];
- j++;
- }
- the_nodes[n2].c[3] = -1;
- the_nodes[n2].cnt --;
- if (the_nodes[n2].cnt == 0)
- the_nodes[n2].cnt = -1;
- }
- #endif
-
-
- int node_closest(float v[3], int nodenum, float mindist) {
-
- int j;
- int mind;
- float dist, dist2;
-
- dist = 10000;
- mind = -1;
- mindist = mindist * mindist;
- for (j=0; j <the_nnodes; j++) {
- if (the_nodes[j].cnt >= 0 &&
- (dist2 = vdistance2(the_nodes[j].pos, v)) < dist &&
- dist2 > mindist &&
- nodenum != j &&
- (nodenum < 0 ||
- (the_nodes[nodenum].c[0] != j &&
- the_nodes[nodenum].c[1] != j &&
- the_nodes[nodenum].c[2] != j &&
- the_nodes[nodenum].c[3] != j))
- ) {
- mind = j;
- dist = dist2;
- }
- }
- return mind;
- }
-
- #ifdef BUILDNODES
- static int node_length(int i) {
- int n1, n2, cnt, prevnode;
-
- n1 = n2 = i;
- cnt = 0;
- prevnode = i;
- while (the_nodes[n1].cnt > 0 && the_nodes[n1].c[0] != -1 &&
- the_nodes[n1].c[0] != prevnode && the_nodes[n1].c[1] != prevnode &&
- cnt < 100) {
- cnt++;
- prevnode = i;
- n1 = the_nodes[n1].c[0];
- }
- prevnode = i;
- while (the_nodes[n2].cnt > 0 && the_nodes[n2].c[1] != -1 &&
- the_nodes[n2].c[1] != prevnode && the_nodes[n2].c[0] != prevnode &&
- cnt < 100) {
- cnt++;
- prevnode = n2;
- n2 = the_nodes[n2].c[1];
- }
- return (cnt);
- }
- #endif
-
- #ifdef BUILDNODES
- static int check_node(float p[3], Matrix *m, int cent) {
-
- int i, j, k, gap;
-
- const float range = PI_DEPTH * 0.30;
- float rs, dist, alpha_s, alpha_p, prev_alpha;
- center_t *center_ptr;
- circle_t *circle_ptr;
- float *wall_ptr;
- float *gap_ptr;
- float pt[3], t1[3];
-
-
- center_ptr = the_level.centers;
- for (i=0; i < the_level.ncenters; i++ ) {
- dist = vdistance(p, center_ptr->center_v);
- /* check distance to points from other centers; no need
- * to check for points that belong to the same center. also is
- * within maximum radius of the center plus a bit extra.
- */
- if (i != cent && dist < center_ptr->radius + PI_DEPTH/2 ) {
- /* point is possibly close enough transform point so it is in
- * coordinate space relative to the center.
- */
- vtransform(p, m[i], pt);
- /* start from outer circle because this is more likely
- * to be close to a point from any other center.
- */
- circle_ptr = center_ptr->circles + center_ptr->ncircles -1;
-
- while (dist < circle_ptr->cradius + PI_DEPTH ) {
- if (dist < circle_ptr->cradius - PI_DEPTH/2) {
- circle_ptr--;
- continue;
- }
- vtransform(circle_ptr->start, m[i], t1);
- rs = sqrtf(SQR(t1[0]) + SQR(t1[1]));
- alpha_s = atan2(t1[1], t1[0]);
- alpha_p = atan2(pt[1], pt[0]);
- if (alpha_s < 0)
- alpha_s += PI2;
- if (alpha_p < 0)
- alpha_p += PI2;
- if (alpha_p < alpha_s)
- alpha_p += PI2;
- wall_ptr = circle_ptr->walls;
- gap_ptr = circle_ptr->gaps;
- /* find segment of circle (gap or wall) in which the
- * point can be found.
- */
- for (j=0; j < circle_ptr->narcs; j++) {
- prev_alpha = alpha_s;
- alpha_s += *wall_ptr++;
- gap = 0;
- if (alpha_p < alpha_s) {
- break;
- }
- prev_alpha = alpha_s;
- alpha_s += *gap_ptr++;
- gap = 1;
- if (alpha_p < alpha_s) {
- break;
- }
- }
- /* if the point is in the sector of a gap, check the
- * distance to the end points on both sides of the gap;
- * else check distance to wall segment.
- */
- if (gap == 1) {
- t1[0] = cos(prev_alpha) * rs;
- t1[1] = sin(prev_alpha) * rs;
- if (vdistance(t1, pt) < range)
- return (0);
- t1[0] = cos(alpha_s) * rs;
- t1[1] = sin(alpha_s) * rs;
- if (vdistance(t1, pt) < range) {
- return (0);
- }
- } else {
- t1[0] = cos(alpha_p) * rs;
- t1[1] = sin(alpha_p) * rs;
- if (vdistance(t1, pt) < range) {
- return(0);
- }
- }
- k--;
- circle_ptr--;
- }
- }
- center_ptr++;
- }
- return (1); /* point well enough outside any walls */
- }
- #endif
-
- #ifdef BUILDNODES
- static int check_remove_node(int i) {
-
- int closest;
- int j, bad, tmp;
- float dist;
-
- if (the_nodes[i].cnt != 2 && the_nodes[i].cnt > 0) {
- if (the_nodes[i].cnt == 1 && the_nodes[the_nodes[i].c[0]].cnt == 1) {
- disconnect_nodes(i, the_nodes[i].c[0]);
- return 1;
- }
- closest = node_closest(the_nodes[i].pos, i, 0.0);
- dist = vdistance(the_nodes[closest].pos, the_nodes[i].pos);
- if (dist > PI_DEPTH*0.375) {
- return 0;
- }
- /* one of those points has to be removed; choose the one on the
- * shortest path. This may not be optimal, but it works
- */
- if (node_length(i) < node_length(closest))
- bad = i;
- else
- bad = closest;
- j = 0;
- while (j < the_nodes[bad].cnt) {
- if ((tmp = the_nodes[bad].c[j]) != -1) {
-
- disconnect_nodes(bad, tmp);
- (void) check_remove_node(tmp);
- }
- else
- j++;
- }
- return 1;
- }
- return 0;
- }
- #endif
-
- /*________________________________________________________________________
- |
- | build_nodes - build a path that runs just between the walls
- |
- | given the data in the maze, construct a path that follows the
- | space between the walls. This will be the path followed by the
- | moving bits in the game.
- | It builds the path for the current level stored in the_level.
- */
-
- #ifdef BUILDNODES
- static void build_nodes(node_t *nodes) {
-
- /* initialy create all nodes lying on the path between all circles
- * and add nodes lying on the gaps in the wall. Then check of none
- * of those nodes is to close to a wall, is they are, remove those
- * nodes from the list. In the next stage, all nodes that are close
- * together are linked.
- */
-
- float t1[3], t2[3], t3[3], t4[3];
- Matrix *m;
- int nstep, i, j, k, n, n1, n2;
- float st_angle;
- center_t *center_ptr;
- circle_t *circle_ptr;
- arc_t *arc_ptr;
- float *wall_ptr;
- float *gap_ptr;
- int thisnode, accepted;
- int narc;
- int closest;
- float dist;
- int done, rejected;
-
- /* first stage generate the rotation matrices; used in other routines */
- m = (Matrix *) alloca(the_level.ncenters * sizeof (Matrix));
- center_ptr = the_level.centers;
- for (i=0; i< the_level.ncenters; i++) {
- vcross(center_ptr->center_v, z_axis, t1);
- mmake_rot_axis(t1,
- -acos(vdot(center_ptr->center_v, z_axis)), m[i]);
- center_ptr++;
- }
-
- /* second stage: add the path in between the walls */
- center_ptr = the_level.centers;
- for (i=0; i < the_level.ncenters; i++) {
- circle_ptr = center_ptr->circles;
- for (j=0; j < center_ptr->ncircles-1 ; j++) {
- wall_ptr = circle_ptr->walls;
- gap_ptr = circle_ptr->gaps;
-
- st_angle = 0.5 / (j + 0.9508);
- vrot_axis(center_ptr->center_v, center_ptr->axis_v,
- (j+0.9508) * PI_DEPTH, t1 );
- vrot_axis(t1, center_ptr->center_v, circle_ptr->rotation,
- t1);
- nstep = PI2/st_angle + 0.5; /* round to nearest int */
- st_angle = PI2/nstep; /* and adjust step angle */
- vrot_axis(t1, center_ptr->center_v, st_angle, t1);
- /* remember the first nod in 'thisnode' so we can connect it
- * too the last node of the circle (when both are accepted)
- */
- if (check_node(t1, m, i)) {
- n = add_node(t1, i);
- accepted = n;
- thisnode = n;
- } else {
- accepted = -1;
- thisnode = -1;
- }
- for (k = 0; k < nstep-1; k++) {
- vrot_axis(t1, center_ptr->center_v, st_angle, t1);
- if (check_node(t1, m, i)) {
- n = add_node(t1, i);
- if (accepted >= 0) {
- connect_nodes(accepted, n);
- }
- accepted = n;
- } else {
- accepted = -1;
- }
- }
- if (thisnode >= 0 && accepted >=0 ) {
- connect_nodes(accepted, thisnode);
- }
- circle_ptr++;
- }
- center_ptr++;
- /* remove the nodes that are too close to other nodes */
- for (j=0; j< the_nnodes; j++) {
- if (the_nodes[j].cnt != 2 && the_nodes[j].cnt > 0) {
- (void)check_remove_node(j);
- }
- }
- }
- /* stage three: add nodes between the gaps */
- center_ptr = the_level.centers;
- for (i=0; i < the_level.ncenters; i++) {
- circle_ptr = center_ptr->circles;
- for (j=0; j < center_ptr->ncircles; j++) {
- wall_ptr = circle_ptr->walls;
- gap_ptr = circle_ptr->gaps;
- narc = circle_ptr->narcs;
-
- st_angle = 0.5 / (j+0.4508); /* half the smallest gap size */
- /* process the gaps of the circle */
- vcopy(circle_ptr->start, t1);
- vcross(center_ptr->center_v,t1, t2);
- vnormal(t2);
- vrot_axis (t1, t2, PI_DEPTH/5, t3);
- vrot_axis (t1, t2, - PI_DEPTH/5, t4);
- for (k = 0 ; k< narc; k++) {
- vrot_axis(t3, center_ptr->center_v, -st_angle, t1);
- vrot_axis(t4, center_ptr->center_v, -st_angle, t2);
- if (check_node(t1, m, i) && check_node(t2, m, i) &&
- vdistance(the_nodes[node_closest(t1, -1, 0.0001)].pos,t1) >
- PI_DEPTH/6 &&
- vdistance(the_nodes[node_closest(t2, -1, 0.0001)].pos,t2) >
- PI_DEPTH/6) {
- n1 = add_node(t1, i);
- rejected = check_remove_node(n1);
- if (!rejected) {
- n2 = add_node(t2, i);
- rejected = check_remove_node(n2);
- }
- } else {
- rejected = 1;
- }
- vrot_axis(t3, center_ptr->center_v, *wall_ptr, t3);
- vrot_axis(t4, center_ptr->center_v, *wall_ptr++, t4);
- if (rejected && *gap_ptr > st_angle * 2) {
- /* add an extra node */
- vrot_axis(t3, center_ptr->center_v, st_angle, t1);
- vrot_axis(t4, center_ptr->center_v, st_angle, t2);
- if (check_node(t1, m, i) && check_node(t2, m, i) &&
- vdistance(the_nodes[node_closest(t1, -1, 0.0001)].pos,t1) >
- PI_DEPTH/6 &&
- vdistance(the_nodes[node_closest(t2, -1, 0.0001)].pos,t2) >
- PI_DEPTH/6 ) {
- n1 = add_node(t1, i);
- rejected = check_remove_node(n1);
- if (!rejected) {
- n2 = add_node(t2, i);
- rejected = check_remove_node(n2);
- }
- } else {
- rejected = 1;
- }
- }
- if (!rejected) {
- connect_nodes(n1, n2);
- closest = node_closest(the_nodes[n].pos, n1, PI_DEPTH*0.025);
- if (closest == -1) continue;
- dist = vdistance(the_nodes[closest].pos, the_nodes[n1].pos);
- if (dist < PI_DEPTH*0.60) {
- connect_nodes(closest, n1);
- }
- closest = node_closest(the_nodes[n2].pos, n2, PI_DEPTH*0.025);
- if (closest == -1) continue;
- dist = vdistance(the_nodes[closest].pos, the_nodes[n2].pos);
- if (dist < PI_DEPTH*0.6) {
- connect_nodes(closest, n2);
- }
- }
- vrot_axis(t3, center_ptr->center_v, *gap_ptr, t3);
- vrot_axis(t4, center_ptr->center_v, *gap_ptr++, t4);
- }
- circle_ptr++;
- }
- center_ptr++;
- }
- /* stage four: add nodes int the center of the circles */
- center_ptr = the_level.centers;
- for (i=0; i < the_level.ncenters; i++) {
- /* the center is always a node, so add it */
- add_node(center_ptr->center_v, i);
- center_ptr++;
- }
-
- /* stage five : connect loose ends that are close together */
- for(i=0; i< the_nnodes; i++) {
- if (the_nodes[i].cnt != 2 && the_nodes[i].cnt >= 0) {
- closest = node_closest(the_nodes[i].pos, i, PI_DEPTH*0.025);
- if (closest == -1) continue;
- dist = vdistance(the_nodes[closest].pos, the_nodes[i].pos);
- if (dist < PI_DEPTH*0.6) {
- connect_nodes(closest, i);
- }
- }
- }
-
- }
- #endif
-
- #ifdef BUILDNODES
- void write_nodes(void) {
-
- FILE *f;
- static char fname[] = "nodes.out";
- int i,j ;
-
- f = fopen(fname, "w+");
- if (f == NULL) {
- fprintf(stderr, "failed to write nodes to %s\n",fname);
- end_sound();
- gexit();
- exit(1);
- }
- fprintf(f, "# number of nodes that follow is %d\n", the_nnodes);
- for (i = 0; i< the_nnodes; i++) {
- fprintf(f, "node(%4d, %3d", i, the_nodes[i].special.all);
- fprintf(f, ", %9.6f, %9.6f, %9.6f", the_nodes[i].pos[0],
- the_nodes[i].pos[1], the_nodes[i].pos[2]);
- for (j=0; j<the_nodes[i].cnt; j++) {
- fprintf(f,", %4d", the_nodes[i].c[j]);
- }
- fprintf(f,");\n");
- }
- fclose(f);
- }
- #endif
-
- static void free_maze(maze_t *maze_ptr) {
-
- level_t *level_ptr;
- center_t *center_ptr;
- circle_t *circle_ptr;
-
- level_ptr = maze_ptr->levels;
- while (maze_ptr->nlevels--) {
- center_ptr = level_ptr->centers;
- while (level_ptr->ncenters--) {
- /* free a center */
- circle_ptr = center_ptr->circles;
- while (center_ptr->ncircles--) {
- /* free an arc */
- free(circle_ptr->arcs);
- free(circle_ptr->walls);
- free(circle_ptr->gaps);
- free(circle_ptr->cappings);
- circle_ptr++;
- }
- free(center_ptr->circles);
- center_ptr++;
- }
- free(level_ptr->centers);
- free(level_ptr->nodes);
- level_ptr++;
- }
- free(maze_ptr->levels);
-
- }
-
- void free_arcs(void) {
-
- center_t *center_ptr;
- circle_t *circle_ptr;
- arc_t *arc_ptr;
- int i, j, k;
-
- center_ptr = the_level.centers;
- for (i = 0; i<the_level.ncenters; i++) {
- circle_ptr = center_ptr->circles;
- for (j = 0; j < center_ptr->ncircles; j++) {
- arc_ptr = circle_ptr->arcs;
- for (k = 0; k < circle_ptr->narcs; k++) {
- if (arc_ptr->wall_obj != 0) {
- if (!isobj(arc_ptr->wall_obj)) {
- fprintf(stderr, "buggy object; ignored\n");
- } else {
- delobj (arc_ptr->wall_obj);
- }
- }
- if (!isobj(arc_ptr->top_obj)) {
- fprintf(stderr, "buggy object; ignored\n");
- } else {
- delobj (arc_ptr->top_obj);
- }
- arc_ptr++;
- }
- circle_ptr++;
- }
- center_ptr++;
- }
- }
-
- extern int mouse_dead;
-
-
- /*_____________________________________________________________________________
- |
- | draw_maze - show all the walls of the maze
- |
- | a trick is used to make the look darker on the shadow side
- | of the planet
- |
- */
-
- void draw_maze(const Matrix m, int zbuf) {
- /* m is the rotation matrix , im its inverse ;
- * zbuf indicates whether the zbuffer is on
- */
-
- int i, j, k;
- int currmat;
- float c;
- int ncenter, ncirc, narc;
- center_t *center_ptr;
- circle_t *circle_ptr;
- arc_t *arc_ptr;
- float t1[3];
- float l1[5]; float l2[5];
- Matrix mm;
-
- /* draw the walls */
- currmat = 0;
- pushmatrix();
- pushmatrix();
- multmatrix(m);
- #ifdef STRANGE_LIGHT
- lmbind(LIGHT0,4);
- #endif
- /*shademodel(GOURAUD);*/
- lmcolor(LMC_SPECULAR);
- ncenter = the_level.ncenters;
- center_ptr = the_level.centers;
- l2[0] = l2[1] = l2[2] = l2[3] = l2[4] = -1;
- if (Lod >= TEXTURE_MAPS && can_do_textures) {
- tevbind(TV_ENV0, 1);
- texbind(TX_TEXTURE_0, 2);
- texgen(TX_S, TG_OFF, NULL);
- texgen(TX_T, TG_OFF, NULL);
- }
- /* check if walls are defined */
- if (center_ptr->circles->arcs->wall_obj != 0 ) {
- for (i= 0; i< ncenter; i++) {
- vtransform( center_ptr->center_v, m, t1);
- #ifdef STRANGE_LIGHT
- if (t1[1] < 0) {
- if (currmat != 3) {
- currmat = 3;
- lmbind(MATERIAL, 3);
- }
- } else {
- if (currmat != 2) {
- currmat = 2;
- lmbind(MATERIAL, 2);
- }
- }
- #else
- if (currmat != 2) {
- currmat = 2;
- lmbind(MATERIAL, 2);
- }
- #endif
- ncirc = center_ptr->ncircles;
- /* trick to make things darker in the shadow of the sphere */
- if (t1[1] < 0 ) {
- c = 1.0+t1[1];
- if (c < 0) c = 0;
- } else c = 1.0;
- l1[0] = LCOLOR;
- l1[1] = 0.7 * c; l1[2] = c; l1[3] = c;
- l1[4] = LMNULL;
- if (l1[0] != l2[0] || l1[1] != l2[1] || l1[2] != l2[2] ) {
- lmdef(DEFLIGHT,1,sizeof(l1), l1);
- l2[0] = l1[0];
- l2[1] = l1[1];
- l2[2] = l1[2];
- }
- circle_ptr = center_ptr->circles+ncirc-1;
- for (j=0; j < ncirc-1; j++) {
- if (t1[2]<0 && circle_ptr->cradius*sqrtf(1-SQR(t1[2]))
- < -t1[2]-EXTRA)
- break;
- narc = circle_ptr->narcs;
- arc_ptr = circle_ptr->arcs;
- for (k = 0; k < narc; k++) {
- callobj ((*arc_ptr++).wall_obj);
- }
- circle_ptr--;
- }
- center_ptr++;
- }
- }
- if (Lod >= TEXTURE_MAPS && can_do_textures) {
- texbind(TX_TEXTURE_0, 0);
- }
- getmatrix(mm);
- popmatrix();
- c = 1.0;
- l1[0] = LCOLOR;
- l1[1] = 0.7 * c; l1[2] = c; l1[3] = c;
- l1[4] = LMNULL;
- if (l1[0] != l2[0] || l1[1] != l2[1] || l1[2] != l2[2] ) {
- lmdef(DEFLIGHT,1,sizeof(l1), l1);
- l2[0] = l1[0];
- l2[1] = l1[1];
- l2[2] = l1[2];
- }
- lmbind(LIGHT0, 1);
- loadmatrix(mm);
- /* draw the top of the walls */
- if (Lod < WALLS_UP && mouse_dead == 0) {
- zbuffer (FALSE);
- }
- lmbind(MATERIAL,4);
- center_ptr = the_level.centers;
- for (i= 0; i< ncenter; i++) {
- ncirc = center_ptr->ncircles;
- circle_ptr = center_ptr->circles+ncirc-1;
- vtransform( center_ptr->center_v, m, t1);
- for (j=0; j < ncirc-1; j++) {
- if (t1[2]<0 && circle_ptr->cradius*sqrtf(1-SQR(t1[2]))
- < -t1[2]-EXTRA)
- break;
- narc = circle_ptr->narcs;
- arc_ptr = circle_ptr->arcs;
- for (k = 0; k < narc; k++) {
- callobj ((*arc_ptr++).top_obj);
- }
- circle_ptr--;
- }
- center_ptr++;
- }
- lmcolor(LMC_COLOR);
- if (Lod < WALLS_UP) {
- zbuffer (zbuf);
- }
-
- #ifdef SHOWPATH
- /* just for debugging, plot the nodes */
- {
- float t1[3];
-
- linewidth(2);
- color(WHITE);
- for (i=0; i< the_nnodes; i++) {
- if (the_nodes[i].cnt >= 0) {
- vcopy(the_nodes[i].pos, t1);
- bgnline();
- vscalar(t1, 1.002);
- v3f(t1);
- vscalar(t1, 1.03);
- v3f(t1);
- if (the_nodes[i].c[0] != -1 &&
- the_nodes[the_nodes[i].c[0]].cnt > 0)
- v3f(the_nodes[the_nodes[i].c[0]].pos);
- if (the_nodes[i].c[1] != -1 &&
- the_nodes[the_nodes[i].c[1]].cnt > 0) {
- v3f(t1);
- v3f(the_nodes[the_nodes[i].c[1]].pos);
- }
- if (the_nodes[i].c[2] != -1 &&
- the_nodes[the_nodes[i].c[2]].cnt > 0) {
- v3f(t1);
- v3f(the_nodes[the_nodes[i].c[2]].pos);
- }
- if (the_nodes[i].c[3] != -1 &&
- the_nodes[the_nodes[i].c[3]].cnt > 0) {
- v3f(t1);
- v3f(the_nodes[the_nodes[i].c[3]].pos);
- }
- endline();
- }
- }
- }
- #endif
- popmatrix();
- }
-
-
-
-